package yhttp

import (
	"crypto/tls"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"
)

var DefHttpClient = http.Client{
	Transport: &http.Transport{
		TLSClientConfig:     &tls.Config{InsecureSkipVerify: true}, //跳过证书的有效认证
		MaxConnsPerHost:     200,
		MaxIdleConns:        100,
		MaxIdleConnsPerHost: 2,
		// 设为true在频次比较搞的情况下，容易出现异常:connectex: Only one usage of each socket address (protocol/network address/port) is normally permitted
		//DisableKeepAlives:     true,
		IdleConnTimeout:       90 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).DialContext,
	},
	Timeout: time.Minute * 2, //设置超时时间，2分钟
}

var DefHttpClient4GetFile = http.Client{
	Transport: &http.Transport{
		TLSClientConfig:       &tls.Config{InsecureSkipVerify: true}, //跳过证书的有效认证
		MaxConnsPerHost:       200,
		MaxIdleConns:          100,
		MaxIdleConnsPerHost:   2,
		IdleConnTimeout:       90 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: -1,
		}).DialContext,
	},
	Timeout: time.Minute * 121, //设置超时时间，121 分钟
}

func HttpGet(url string) (respBuf []byte, err error) {
	resp, err := DefHttpClient.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 &&
		resp.StatusCode != http.StatusTemporaryRedirect &&
		resp.StatusCode != http.StatusPermanentRedirect {
		buf, _ := io.ReadAll(resp.Body)
		var msg string
		if len(buf) > 0 {
			msg = string(buf)
			return nil, fmt.Errorf("%d %s", resp.StatusCode, msg)
		} else {
			msg = resp.Status
			return nil, fmt.Errorf("%s", msg)
		}
	}

	return io.ReadAll(resp.Body)
}

func DefaultHttpGet(url string) (resp *http.Response, err error) {
	return DefHttpClient.Get(url)
}

func DefaultHttpGetRespBuf(url string) (respBuf []byte, err error) {
	resp, err := DefHttpClient.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return io.ReadAll(resp.Body)
}

func DefaultHttpPostString(url, contentType string, bodyStr string) (respBuf []byte, err error) {
	resp, err := DefHttpClient.Post(url, contentType, strings.NewReader(bodyStr))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return io.ReadAll(resp.Body)
}

func DefaultHttpPostStringEx(url, contentType string, bodyStr string, beforePost func(req *http.Request)) (respBuf []byte, err error) {
	req, e1 := http.NewRequest("POST", url, strings.NewReader(bodyStr))
	if e1 != nil {
		return nil, e1
	}
	req.Header.Set("Content-Type", contentType)
	if beforePost != nil {
		beforePost(req)
	}

	resp, err := DefHttpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return io.ReadAll(resp.Body)
}

func DefaultHttpPost(url, contentType string, body io.Reader) (resp *http.Response, err error) {
	//return http.Post(url, contentType, body)
	return DefHttpClient.Post(url, contentType, body)
}

func DefaultHttpPostRespBuf(url, contentType string, body io.Reader, beforePost func(req *http.Request)) (respBuf []byte, err error) {
	req, e1 := http.NewRequest("POST", url, body)
	if e1 != nil {
		return nil, e1
	}
	req.Header.Set("Content-Type", contentType)
	if beforePost != nil {
		beforePost(req)
	}

	resp, err := DefHttpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return io.ReadAll(resp.Body)
}

func DefaultHttpPostEx(url, contentType string, body io.Reader, beforePost func(req *http.Request)) (resp *http.Response, err error) {
	req, e1 := http.NewRequest("POST", url, body)
	if e1 != nil {
		return nil, e1
	}
	req.Header.Set("Content-Type", contentType)
	if beforePost != nil {
		beforePost(req)
	}
	return DefHttpClient.Do(req)
}

func DefaultHttpPostForm(url string, data url.Values, beforePost func(req *http.Request)) (resp *http.Response, err error) {
	return DefaultHttpPostEx(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()), beforePost)
}

func DefaultHttpPostFormBuf(url string, data url.Values, beforePost func(req *http.Request)) (respBuf []byte, err error) {
	resp, err := DefaultHttpPostEx(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()), beforePost)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}
